import 'dart:convert';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:ichinesereader/constants.dart';
import 'package:ichinesereader/models/assessment/assessmentRecordsResult.dart';
import 'package:ichinesereader/models/assessment/assessmentTeacherQueryDto.dart';
import 'package:ichinesereader/models/book/BookDetails.dart';
import 'package:ichinesereader/models/book/BookQuiz.dart';
import 'package:ichinesereader/models/book/book.dart';
import 'package:ichinesereader/models/evaluation/evaluationOverviewResult.dart';
import 'package:ichinesereader/models/report/assignmentStudentData.dart';
import 'package:ichinesereader/models/report/assignmentStudentDetail.dart';
import 'package:ichinesereader/models/report/basketsResult.dart';
import 'package:ichinesereader/models/report/childrenHistoryResult.dart';
import 'package:ichinesereader/models/report/classLiveAssignmentsResult.dart';
import 'package:ichinesereader/models/report/classOverviewDetailsResult.dart';
import 'package:ichinesereader/models/report/classOverviewTotal.dart';
import 'package:ichinesereader/models/report/classProficiencyResult.dart';
import 'package:ichinesereader/models/report/classSkillsResult.dart';
import 'package:ichinesereader/models/report/classStudentReportResult.dart';
import 'package:ichinesereader/models/report/classlevelchartdata.dart';
import 'package:ichinesereader/models/report/classskillchartdata.dart';
import 'package:ichinesereader/models/report/fileLocationResult.dart';
import 'package:ichinesereader/models/report/libraryKnowledgeClassResult.dart';
import 'package:ichinesereader/models/report/libraryKnowledgeUserResult.dart';
import 'package:ichinesereader/models/report/quizRecordData.dart';
import 'package:ichinesereader/models/report/readHistoryResult.dart';
import 'package:ichinesereader/models/report/selfReadingData.dart';
import 'package:ichinesereader/models/report/selfReadingDto.dart';
import 'package:ichinesereader/models/report/singleAssignmentData.dart';
import 'package:ichinesereader/models/report/studentActivityDto.dart';
import 'package:ichinesereader/models/report/studentActivityResult.dart';
import 'package:ichinesereader/models/report/studentLevelProgress.dart';
import 'package:ichinesereader/models/report/studentStats.dart';
import 'package:ichinesereader/models/school/SchoolStaticsData.dart';
import 'package:ichinesereader/models/student/Assignments.dart';
import 'package:ichinesereader/models/student/StudentItem.dart';
import 'package:ichinesereader/models/student/assignmentSearchDto.dart';
import 'package:ichinesereader/pages/common/report/reportsStudentPersonalContent.dart';
import 'package:ichinesereader/service/book.dart';
import 'package:ichinesereader/service/evaluation.dart';
import 'package:ichinesereader/service/schooladmin.dart';
import 'package:ichinesereader/service/student.dart';
import 'package:ichinesereader/models/common/StatusMessageResult.dart';
import 'package:ichinesereader/utils/log.dart';

class ReportsController extends GetxController with StateMixin<dynamic> {
  StudentServiceProvider _studentServiceProvider = new StudentServiceProvider();
  SchoolAdminServiceProvider _schoolServiceProvider =
      new SchoolAdminServiceProvider();

  //SchoolAdminController _schoolAdminController = Get.find();
  EvaluationServiceProvider _evaluationServiceProvider =
      new EvaluationServiceProvider();
  BookServiceProvider _bookServiceProvider = new BookServiceProvider();

  Rx<StatusMessageResult> _statusMessageResult =
      Rx<StatusMessageResult>(StatusMessageResult());

  Rx<StatusMessageResult> get statusMessageResult => this._statusMessageResult;
  StatusMessageResult _statusResult = new StatusMessageResult();

  List<Assignment> _assignmentRecords = <Assignment>[].obs;

  List<Assignment> get assignmentRecords => this._assignmentRecords;

  List<BasketItem> _basketItems = <BasketItem>[].obs;

  List<BasketItem> get basketItem => this._basketItems;
  List<HistoryResult> _readHistories = <HistoryResult>[].obs;

  List<HistoryResult> get readHistories => this._readHistories;
  List<StudentItem> _studentItems = <StudentItem>[].obs;

  Rx<ClassOverviewTotalData> _classoverviewtotal =
      Rx<ClassOverviewTotalData>(ClassOverviewTotalData());
  Rx<ClassSkillsResult> _classskillstotal =
      Rx<ClassSkillsResult>(ClassSkillsResult());
  Rx<ClassProficiencyResult> _classproficiencyresult =
      Rx<ClassProficiencyResult>(ClassProficiencyResult());
  List<ClassLevelChartData> _classleveldata = <ClassLevelChartData>[].obs;
  Rx<ClassAssignmentsResult> _classassignmentsresult =
      Rx<ClassAssignmentsResult>(ClassAssignmentsResult());
  List<List<ClassSkillChartData>> _classskilldata =
      List<List<ClassSkillChartData>>.filled(6, []).obs;
  Rx<ClassStudentReportResult> _classstudentreport =
      Rx<ClassStudentReportResult>(ClassStudentReportResult());
  List<StudentLevelProgress> _studentLevelProgress =
      <StudentLevelProgress>[].obs;
  List<Book> _studentHistoryResult = <Book>[].obs;
  List<BookDetails> _studentHistoryResultBook = <BookDetails>[].obs;
  Rx<SchoolStaticsData> _schoolStaticsData =
      Rx<SchoolStaticsData>(SchoolStaticsData());
  Rx<SchoolStaticsData> _schoolStaticsDataMonth =
      Rx<SchoolStaticsData>(SchoolStaticsData());
  List<StudentStats> _studentStatics = <StudentStats>[].obs;
  Rx<FileLoactionResult> _allClassReport =
      Rx<FileLoactionResult>(FileLoactionResult());
  Rx<ClassOverviewDetailsResult> _classoverviewdetailsresult =
      Rx<ClassOverviewDetailsResult>(ClassOverviewDetailsResult());
  Rx<ClassSkillsResult> _studentSkillTotal =
      Rx<ClassSkillsResult>(ClassSkillsResult());
  List<List<ClassSkillChartData>> _studentSkillData =
      List<List<ClassSkillChartData>>.filled(6, []).obs;
  Rx<StudentActivityResult> _studentActivity =
      Rx<StudentActivityResult>(StudentActivityResult());
  RxString _recordingLocation = ''.obs;
  List<QuestionRecord> _quizBookItems = <QuestionRecord>[].obs;
  Rx<FileLoactionResult> _gradeReport =
      Rx<FileLoactionResult>(FileLoactionResult());

  List<SingleAssignmentData> _singleAssignmentData =
      <SingleAssignmentData>[].obs;
  Rx<EvaluationOverViewData> _quickReviewOverviewResult =
      Rx<EvaluationOverViewData>(EvaluationOverViewData());
  Rx<LibraryKnowledgeClassData> _libraryKnowledgeClassData =
      Rx<LibraryKnowledgeClassData>(LibraryKnowledgeClassData());
  Rx<LibraryKnowledgeUserData> _libraryKnowledgeUserData =
      Rx<LibraryKnowledgeUserData>(LibraryKnowledgeUserData());

  Rx<ClassOverviewTotalData> get classoverviewtotal => this._classoverviewtotal;

  Rx<ClassSkillsResult> get classskillstotal => this._classskillstotal;

  Rx<ClassProficiencyResult> get classproficiencyresult =>
      this._classproficiencyresult;

  List<ClassLevelChartData> get classleveldata => this._classleveldata;

  Rx<ClassAssignmentsResult> get classassignmentsresult =>
      this._classassignmentsresult;

  List<List<ClassSkillChartData>> get classskilldata => this._classskilldata;

  Rx<ClassStudentReportResult> get classstudentreport =>
      this._classstudentreport;

  List<StudentLevelProgress> get studentLevelProgress =>
      this._studentLevelProgress;

  List<Book> get studentHistoryResult => this._studentHistoryResult;

  List<BookDetails> get studentHistoryResultBook =>
      this._studentHistoryResultBook;

  List<StudentItem> get studentItems => this._studentItems;

  Rx<SchoolStaticsData> get schoolStaticsData => this._schoolStaticsData;

  Rx<SchoolStaticsData> get schoolStaticsDataMonth =>
      this._schoolStaticsDataMonth;

  List<StudentStats> get studentStatics => this._studentStatics;

  Rx<FileLoactionResult> get allClassReport => this._allClassReport;

  Rx<ClassOverviewDetailsResult> get classoverviewdetailsresult =>
      this._classoverviewdetailsresult;

  Rx<ClassSkillsResult> get studentSkillTotal => this._studentSkillTotal;

  List<List<ClassSkillChartData>> get studentSkillData =>
      this._studentSkillData;

  Rx<StudentActivityResult> get studentActivity => this._studentActivity;

  List<BasketItem> get basketItems => this._basketItems;

  Rx<String> get recordingLocation => this._recordingLocation;

  List<QuestionRecord> get quizBookItems => this._quizBookItems;
  Rx<AssessmentRecordsResult> _teacherAssessmentRecord =
      Rx<AssessmentRecordsResult>(AssessmentRecordsResult());

  Rx<AssessmentRecordsResult> get teacherAssessmentRecord =>
      this._teacherAssessmentRecord;

  Rx<FileLoactionResult> get gradeReport => this._gradeReport;

  List<SingleAssignmentData> get singleAssignmentData =>
      this._singleAssignmentData;

  Rx<EvaluationOverViewData> get quickReviewOverviewResult =>
      this._quickReviewOverviewResult;

  Rx<AssignmentStudentData> _assignmentStudentData =
      Rx<AssignmentStudentData>(AssignmentStudentData());

  Rx<AssignmentStudentData> get assignmentStudentData =>
      this._assignmentStudentData;

  List<AssignmentStudentDetail> _assignmentStudentDetailList =
      <AssignmentStudentDetail>[].obs;

  List<AssignmentStudentDetail> get assignmentStudentDetailList =>
      this._assignmentStudentDetailList;
  Rx<SelfReadingData> _selfReadingData = Rx<SelfReadingData>(SelfReadingData());

  Rx<SelfReadingData> get selfReadingData => this._selfReadingData;
  Rx<QuizRecordData> _quizRecordData = Rx<QuizRecordData>(QuizRecordData());

  Rx<QuizRecordData> get quizRecordData => this._quizRecordData;
  Rx<BookQuiz> _bookquiz = Rx<BookQuiz>(BookQuiz());

  Rx<BookQuiz> get bookquiz => this._bookquiz;

  Rx<LibraryKnowledgeClassData> get libraryKnowledgeClassData =>
      this._libraryKnowledgeClassData;

  Rx<LibraryKnowledgeUserData> get libraryKnowledgeUserData =>
      this._libraryKnowledgeUserData;
  List<QuestionRecord> _quickReviewLibraryRecordItems = <QuestionRecord>[].obs;

  List<QuestionRecord> get quickReviewLibraryRecordItems =>
      this._quickReviewLibraryRecordItems;

  @override
  void onInit() {
    super.onInit();
  }

  @override
  dispose() {
    super.dispose();
  }

  Future<dynamic> fetchStudentBaskets() async {
    var basketData = <BasketItem>[];
    try {
      EasyLoading.show();
      var response = await _studentServiceProvider.getReportBaskets('200', '0');
      if (response.statusCode == 200) {
        var data = basketsResultFromJson(response.body);
        _basketItems.assignAll(data.list as List<BasketItem>);

        if (_basketItems.isNotEmpty) {
          basketData = data.list as List<BasketItem>;
          change(_basketItems, status: RxStatus.success());
        } else {
          change(_basketItems, status: RxStatus.empty());
        }
      } else {
        change(null, status: RxStatus.error(''));
      }
    } catch (error) {
      change(null, status: RxStatus.error(''));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    return basketData;
  }

  Future<dynamic> fetchMyReadingRecords() async {
    var historyData = <HistoryResult>[];
    try {
      EasyLoading.show();
      var response = await _studentServiceProvider.getReadingRecords();
      if (response.statusCode == 200) {
        var data = historyResultFromJson(response.body);
        _readHistories.assignAll(data);
        historyData = data;
        change(_readHistories, status: RxStatus.success());
      } else {
        change(_readHistories, status: RxStatus.empty());
      }
    } catch (error) {
      change(_readHistories, status: RxStatus.empty());
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    return historyData;
  }

  void fetchStudentAssignmentRecordsByClass(String classId) async {
    try {
      //change(_assignmentRecords, status: RxStatus.loading());
      EasyLoading.show();
      var response =
          await _studentServiceProvider.getAssignmentRecordsByClass(classId);
      if (response.statusCode == 200) {
        var data = assignmentsFromJson(response.body);
        //Log.debug(data.length);
        data.sort((a, b) {
          int end1 = a.assignment!.endDateUtc!.toInt();
          var end2 = b.assignment!.endDateUtc!.toInt();
          return end2.compareTo(end1);
        });
        _assignmentRecords.assignAll(data);
        if (_assignmentRecords.isNotEmpty) {
          change(_assignmentRecords, status: RxStatus.success());
        } else {
          change(null, status: RxStatus.empty());
        }
      } else {
        change(null, status: RxStatus.error());
      }
    } catch (error) {
      change(null, status: RxStatus.error());
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchClassOverviewTotalData(
      String classId, String? startTime, String? endTime) async {
    try {
      change(_classoverviewtotal, status: RxStatus.loading());
      _statusResult = new StatusMessageResult();
      var response = await _schoolServiceProvider
          .getClassOverviewTotalByClassId(classId, startTime, endTime);
      if (response.statusCode == 200) {
        var data = classOverviewDataFromJson(response.bodyString);
        this._classoverviewtotal.value = data;
        _statusResult.status = 1000;
        _statusResult.message = 'Success';
        change(_classoverviewtotal, status: RxStatus.success());
      } else {
        change(_classoverviewtotal, status: RxStatus.success());
        _statusResult.status = response.statusCode;
        _statusResult.message = 'Failed';
      }
    } catch (error) {
      change(_classoverviewtotal, status: RxStatus.error());
      _statusResult.status = 0;
      _statusResult.message = 'Oops, something wrong ...'.tr;
      Log.debug(error);
    }
    _statusMessageResult.value = _statusResult;
  }

  void fetchClassOverviewDetails(
      String classId, String? startTime, String? endTime) async {
    try {
      EasyLoading.show();
      _statusResult = new StatusMessageResult();
      var response = await _schoolServiceProvider
          .getClassOverviewDetailsByClassId(classId, startTime, endTime);
      change(this._classoverviewdetailsresult, status: RxStatus.success());
      if (response.statusCode == 200) {
        var data = classOverviewDetailsResultFromJson(response.bodyString);
        this._classoverviewdetailsresult.value = data;
        _statusResult.status = 1000;
        _statusResult.message = 'Success';
      } else {
        _statusResult.status = response.statusCode;
        _statusResult.message = 'Failed';
      }
    } catch (error) {
      change(this._classoverviewdetailsresult, status: RxStatus.error());
      _statusResult.status = 0;
      _statusResult.message = 'Oops, something wrong ...'.tr;
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    _statusMessageResult.value = _statusResult;
  }

  void fetchClassProficiencyLevelData(String classId) async {
    try {
      _statusResult = new StatusMessageResult();
      change(_classproficiencyresult, status: RxStatus.loading());
      change(_classleveldata, status: RxStatus.loading());
      var response =
          await _schoolServiceProvider.getClassOverviewLevelsByClassId(classId);
      if (response.statusCode == 200) {
        this._classleveldata.clear();
        var data = classProficiencyResultFromJson(response.bodyString);
        this._classproficiencyresult.value = data;
        if (data.result!.level != null) {
          data.result!.level!.forEach((key, value) {
            this._classleveldata.add(new ClassLevelChartData(key, value));
          });
        }
        _statusResult.status = 1000;
        _statusResult.message = 'Success';
      } else {
        _statusResult.status = response.statusCode;
        _statusResult.message = 'Failed';
      }
      change(_classproficiencyresult, status: RxStatus.success());
      change(_classleveldata, status: RxStatus.success());
    } catch (error) {
      change(_classproficiencyresult, status: RxStatus.error());
      change(_classleveldata, status: RxStatus.error());
      _statusResult.status = 0;
      _statusResult.message = 'Oops, something wrong ...'.tr;
      Log.debug(error);
    }
    _statusMessageResult.value = _statusResult;
  }

  void fetchClassAssignmentsData(
      String classId, AssignmentSearchDto dto) async {
    try {
      EasyLoading.show();
      _statusResult = new StatusMessageResult();
      var response = await _schoolServiceProvider.getClassAssignmentsByClassId(
          classId, dto);
      if (response.statusCode == 200) {
        ClassAssignmentsResult data =
            classAssignmentsResultFromJson(response.bodyString);
        this._classassignmentsresult.value = data;
        _statusResult.status = 1000;
        _statusResult.message = 'Success';
      } else {
        _statusResult.status = response.statusCode;
        _statusResult.message = 'Failed';
      }
      change(_classassignmentsresult, status: RxStatus.success());
    } catch (error) {
      _statusResult.status = 0;
      _statusResult.message = 'Oops, something wrong ...'.tr;
      Log.debug(error);
      change(_classassignmentsresult, status: RxStatus.error());
    } finally {
      EasyLoading.dismiss();
    }
    _statusMessageResult.value = _statusResult;
  }

  void fetchClassSkillsData(String classId, bool firsttemp) async {
    try {
      _statusResult = new StatusMessageResult();
      change(_classskillstotal, status: RxStatus.loading());
      change(_classskilldata, status: RxStatus.loading());
      var response = await _schoolServiceProvider.getClassSkillsByClassId(
          classId, firsttemp);
      if (response.statusCode == 200) {
        var data = classSkillsResultFromJson(response.bodyString);
        this._classskillstotal.value = data;
        if (data.result!.dataList != null) {
          data.result!.dataList!.forEach((element) {
            int index = element.parentid!;
            List<ClassSkillChartData> list = [];
            if (this._classskilldata[index].isNotEmpty) {
              list = this._classskilldata[index];
            }
            var newData = ClassSkillChartData(
                element.name!.replaceAll("/", "\n"), element.value);
            list.add(newData);
            this._classskilldata[index] = list;
          });
        }
        _statusResult.status = 1000;
        _statusResult.message = 'Success';
      } else {
        _statusResult.status = response.statusCode;
        _statusResult.message = 'Failed';
      }
      change(_classskillstotal, status: RxStatus.success());
      change(_classskilldata, status: RxStatus.success());
    } catch (error) {
      _statusResult.status = 0;
      _statusResult.message = 'Oops, something wrong ...'.tr;
      Log.debug(error);
      change(_classskillstotal, status: RxStatus.error());
      change(_classskilldata, status: RxStatus.error());
    }
    _statusMessageResult.value = _statusResult;
  }

  void fetchClassStudentReportByClass(
      String classId, String userName, AssignmentSearchDto dto) async {
    try {
      EasyLoading.show();
      //change(null, status: RxStatus.loading());
      var response = await _schoolServiceProvider
          .getClassStudentReportByClassId(classId, userName, dto);
      if (response.statusCode == 200) {
        var data = classStudentReportResultFromJson(response.bodyString);
        this._classstudentreport.value = data;
        change(this._classstudentreport, status: RxStatus.success());
      }
    } catch (error) {
      change(this._classstudentreport, status: RxStatus.error());
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchStudentHistoryResults(String userName) async {
    try {
      _statusResult = new StatusMessageResult();
      _studentHistoryResult.clear();
      _studentHistoryResultBook.clear();
      var response = await _studentServiceProvider.getChildrenHistory(userName);
      if (response.statusCode == 200) {
        var data = childrenHistoryResultFromJson(response.bodyString);
        this._studentHistoryResult.assignAll(data);
        data.forEach(
          (element) {
            if (element.book != null) {
              this._studentHistoryResultBook.add(element.book!);
            }
          },
        );
        _statusResult.status = 1000;
        _statusResult.message = 'Success';
      } else {
        _statusResult.status = response.statusCode;
        _statusResult.message = 'Failed';
      }
      change(this._studentHistoryResult, status: RxStatus.success());
      change(this._studentHistoryResultBook, status: RxStatus.success());
    } catch (error) {
      _statusResult.status = 0;
      _statusResult.message = 'Oops, something wrong ...'.tr;
      Log.debug(error);
    }
    _statusMessageResult.value = _statusResult;
  }

  void fetchStudentLevelProgress(String userName) async {
    try {
      EasyLoading.show();
      var response =
          await _schoolServiceProvider.getStudentLevelProgress(userName);
      if (response.statusCode == 200) {
        _studentItems.clear();
        var data = studentLevelProgressFromJson(response.bodyString);
        this._studentLevelProgress.assignAll(data);
        change(_studentLevelProgress, status: RxStatus.success());
      }
    } catch (error) {
      change(null, status: RxStatus.error());
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchSchoolStatisticList(
      String startTime, String endTime, bool isYear, bool isLast) async {
    try {
      EasyLoading.show();
      if (isYear) {
        //change(_schoolStaticsData, status: RxStatus.loading());
        var response = await _schoolServiceProvider.getSchoolStatisticList(
            startTime, endTime, isYear);
        if (response.statusCode == 200) {
          var data = schoolStaticsDataFromJson(response.bodyString);
          this._schoolStaticsData.value = data;
          change(_schoolStaticsData, status: RxStatus.success());
        } else {
          change(null, status: RxStatus.error());
        }
      } else {
        if (this._schoolStaticsDataMonth.value.result != null) {
          if (!this
              ._schoolStaticsDataMonth
              .value
              .result!
              .dataMap!
              .containsKey(startTime)) {
            //change(_schoolStaticsDataMonth, status: RxStatus.loading());
            var response = await _schoolServiceProvider.getSchoolStatisticList(
                startTime, endTime, isYear);
            if (response.statusCode == 200) {
              var data = schoolStaticsDataFromJson(response.bodyString);
              SchoolStaticsData newOne = new SchoolStaticsData();
              newOne = this.schoolStaticsDataMonth.value;
              newOne.result!.dataMap = {
                ...?newOne.result!.dataMap,
                ...?data.result!.dataMap
              };
              this._schoolStaticsDataMonth.value = newOne;
              if (isLast) {
                change(_schoolStaticsDataMonth, status: RxStatus.success());
                change(_schoolStaticsData, status: RxStatus.success());
              } else {
                change(_schoolStaticsDataMonth, status: RxStatus.loading());
                change(_schoolStaticsData, status: RxStatus.loading());
              }
            } else {
              change(null, status: RxStatus.error());
            }
          }
        } else {
          //change(_schoolStaticsDataMonth, status: RxStatus.loading());
          var response = await _schoolServiceProvider.getSchoolStatisticList(
              startTime, endTime, isYear);
          if (response.statusCode == 200) {
            var data = schoolStaticsDataFromJson(response.bodyString);
            this._schoolStaticsDataMonth.value = data;
            change(_schoolStaticsDataMonth, status: RxStatus.success());
            change(_schoolStaticsData, status: RxStatus.success());
          } else {
            change(null, status: RxStatus.error());
          }
        }
      }
    } catch (error) {
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void schoolStaticsDataMonthClear() {
    this._schoolStaticsDataMonth.value = new SchoolStaticsData();
  }

  void downloadAllClassReport() async {
    change(this._allClassReport, status: RxStatus.loading());
    try {
      var response = await _schoolServiceProvider.downloadAllClassReport();
      if (response.statusCode == 200) {
        var data = fileLoactionResultFromJson(response.bodyString);
        this._allClassReport.value = data;
        change(this._allClassReport, status: RxStatus.success());
      }
    } catch (error) {
      change(this._allClassReport, status: RxStatus.error());
      Log.debug(error);
    }
  }

  void fetchStudentStatics(String username) async {
    try {
      this._studentStatics.clear();
      var response =
          await _schoolServiceProvider.getStudentStatics(username.trim());
      if (response.statusCode == 200) {
        var data = studentStatsFromJson(response.bodyString);
        this._studentStatics.assignAll(data);
        change(this._studentStatics, status: RxStatus.success());
      }
    } catch (error) {
      change(this._studentStatics, status: RxStatus.error());
      Log.debug(error);
    }
  }

  void fetchStudentSkillsByUsername(
      String userName, String? endTime, bool? isFirstAttempt) async {
    try {
      EasyLoading.show();
      var response = await _schoolServiceProvider.getStudentSkillsByUsername(
          userName, endTime, isFirstAttempt);
      if (response.statusCode == 200) {
        var data = classSkillsResultFromJson(response.bodyString);
        this._studentSkillTotal.value = data;
        if (data.result!.dataList != null) {
          data.result!.dataList!.forEach((element) {
            int index = element.parentid!;
            List<ClassSkillChartData> list = [];
            if (this._studentSkillData[index].isNotEmpty) {
              list = this._studentSkillData[index];
            }
            var newData = ClassSkillChartData(
                element.name!.replaceAll("/", "\n"), element.value);
            list.add(newData);
            this._studentSkillData[index] = list;
          });
        }
      }
      change(_studentSkillTotal, status: RxStatus.success());
      change(_studentSkillData, status: RxStatus.success());
    } catch (error) {
      Log.debug(error);
      change(_studentSkillTotal, status: RxStatus.error());
      change(_studentSkillData, status: RxStatus.error());
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchStudentActivity(
      String classId, String userName, StudentActivityDto dto) async {
    try {
      EasyLoading.show();
      var response = await _schoolServiceProvider.getStudentActivity(
          classId, userName, dto);
      if (response.statusCode == 200) {
        var data = studentActivityResultFromJson(response.bodyString);
        this._studentActivity.value = data;
      }
      change(_studentActivity, status: RxStatus.success());
    } catch (error) {
      Log.debug(error);
      change(_studentActivity, status: RxStatus.error());
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchTeacherBaskets(
      String classId, List<String> content, List<String> status) async {
    try {
      EasyLoading.show();
      var response = await _schoolServiceProvider.getReportBaskets(
          classId, content, status, '300', '');
      if (response.statusCode == 200) {
        var data = basketsResultFromJson(response.bodyString);
        _basketItems.assignAll(data.list as List<BasketItem>);

        if (_basketItems.isNotEmpty) {
          change(_basketItems, status: RxStatus.success());
        } else {
          change(_basketItems, status: RxStatus.empty());
        }
      } else {
        change(null, status: RxStatus.error(''));
      }
    } catch (error) {
      change(null, status: RxStatus.error(''));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  Future<StatusMessageResult> removeFromBasket(
      String classId, String id) async {
    var _statusResult = new StatusMessageResult();
    try {
      EasyLoading.show();
      var response = await _schoolServiceProvider.removeFromBasket(classId, id);
      if (response.statusCode == 200) {
        _statusResult.status = 1000;
        _basketItems.removeWhere((element) => element.id == id);
        if (_basketItems.isNotEmpty) {
          change(_basketItems, status: RxStatus.success());
        } else {
          change(_basketItems, status: RxStatus.empty());
        }
      } else {
        _statusResult.status = 0;
      }
    } catch (error) {
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    return _statusResult;
  }

  void basketReview(String type, String userName, String bookId,
      String? assignmentId, String? basketId) async {
    try {
      var response = await _schoolServiceProvider.basketReview(
          type, userName, bookId, assignmentId);
      if (response.statusCode == 200) {
        if (this._basketItems.isNotEmpty && basketId != null) {
          var index = _basketItems.indexWhere((element) =>
              element.assignmentId == assignmentId &&
              element.bookId == bookId &&
              element.player!.userName == userName);
          if (index != -1) {
            this._basketItems[index].status = 'REVIEWED';
            change(this._basketItems, status: RxStatus.success());
          }
        }
        if (this._selfReadingData.value.list != null && basketId == null) {
          int? index = -1;
          if (type == 'recording' || type == 'RECORDING') {
            index = _selfReadingData.value.list?.indexWhere((element) =>
                element.bookId == bookId &&
                element.recording?.student?.userName == userName);
            if (index != -1) {
              this._selfReadingData.value.list?[index!].recording?.status =
                  'REVIEWED';
              change(this._selfReadingData, status: RxStatus.success());
            }
          } else {
            index = _selfReadingData.value.list?.indexWhere((element) =>
                element.bookId == bookId &&
                element.writing?.student?.userName == userName);

            if (index != -1) {
              this._selfReadingData.value.list?[index!].writing?.status =
                  'REVIEWED';
              change(this._selfReadingData, status: RxStatus.success());
            }
          }
        }
      }
    } catch (error) {
      Log.debug(error);
    }
  }

  void getRecordingFile(String fileId) async {
    try {
      change(_recordingLocation, status: RxStatus.loading());
      var response = await _schoolServiceProvider.downloadFileLocation(fileId);
      _recordingLocation.value = jsonDecode(response.bodyString)['location'];
      change(_recordingLocation, status: RxStatus.success());
    } catch (error) {
      change(_recordingLocation, status: RxStatus.error(''));
      Log.debug(error);
    }
  }

  Future<String> fetchRecordingFile(String fileId) async {
    String _recordingFile = '';
    try {
      var response = await _schoolServiceProvider.downloadFileLocation(fileId);
      _recordingFile = jsonDecode(response.bodyString)['location'] ?? '';
    } catch (error) {
      Log.debug(error);
    }
    return _recordingFile;
  }

  void basketGrade(
      String type,
      String userName,
      String bookId,
      String? assignmentId,
      String grade,
      String? comment,
      String? basketId) async {
    try {
      if (basketId != null) {
        change(_basketItems, status: RxStatus.loading());
      }
      var response = await _schoolServiceProvider.basketGrade(
          type, userName, bookId, assignmentId, grade, comment);
      if (response.statusCode == 200) {
        if (basketId != null && this._basketItems.isNotEmpty) {
          var index = _basketItems.indexWhere((element) =>
              element.assignmentId == assignmentId &&
              element.bookId == bookId &&
              element.player!.userName == userName);
          if (index != -1) {
            _basketItems[index].status = "GRADED";
            _basketItems[index].content!.grade = grade;
            _basketItems[index].content!.comment = comment;
            change(_basketItems, status: RxStatus.success());
          }
        }

        if (basketId == null && this.selfReadingData.value.list != null) {
          int? index = -1;
          if (type == 'recording' || type == 'RECORDING') {
            index = _selfReadingData.value.list?.indexWhere((element) =>
                element.bookId == bookId &&
                element.recording?.student?.userName == userName);

            if (index != -1) {
              this._selfReadingData.value.list?[index!].recording?.status =
                  'GRADED';
              this._selfReadingData.value.list?[index!].recording?.comment =
                  comment;
              this._selfReadingData.value.list?[index!].recording?.grade =
                  grade;
              change(this._selfReadingData, status: RxStatus.success());
            }
          } else {
            index = _selfReadingData.value.list?.indexWhere((element) =>
                element.bookId == bookId &&
                element.writing?.student?.userName == userName);

            if (index != -1) {
              this._selfReadingData.value.list?[index!].writing?.status =
                  'GRADED';
              this._selfReadingData.value.list?[index!].writing?.comment =
                  comment;
              this._selfReadingData.value.list?[index!].writing?.grade = grade;
              change(this._selfReadingData, status: RxStatus.success());
            }
          }
        }
      } else {
        change(null, status: RxStatus.error(''));
      }
    } catch (error) {
      Log.debug(error);
    }
  }

  void getQuizBookRecordsByClass(
      String classId, String type, String? limit, String? page) async {
    try {
      EasyLoading.show();
      var response = await _evaluationServiceProvider.getQuizBookRecordsByClass(
          limit, page, type, classId);
      if (response.statusCode == 200) {
        var data = assessmentRecordsResultFromJson(response.bodyString);
        _quizBookItems.assignAll(data.list as List<QuestionRecord>);
        if (_quizBookItems.length > 0) {
          _quizBookItems.sort((a, b) {
            var end1 = a.committedTime as int;
            var end2 = b.committedTime as int;
            return end2.compareTo(end1);
          });
          change(_quizBookItems, status: RxStatus.success());
        } else {
          change(null, status: RxStatus.empty());
        }
      } else {
        change(null, status: RxStatus.empty());
      }
    } catch (error) {
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchTeacherAssessmentRecords(
      String classId, AssessmentTeacherQueryDto dto) async {
    try {
      EasyLoading.show();
      var response = await _schoolServiceProvider.getTeacherAssessmentRecords(
          classId, dto);
      if (response.statusCode == 200) {
        var data = assessmentRecordsResultFromJson(response.bodyString);
        if (data.list!.length > 0) {
          data.list!.removeWhere((element) => element.type == 'BENCHMARK_TEST');
          change(_teacherAssessmentRecord, status: RxStatus.success());
          this._teacherAssessmentRecord.value = data;
        } else {
          change(_teacherAssessmentRecord, status: RxStatus.empty());
        }
      }
    } catch (error) {
      Log.debug(error);
      change(_teacherAssessmentRecord, status: RxStatus.error());
    } finally {
      EasyLoading.dismiss();
    }
  }

  // Future<List<QuestionRecord>> fetchTeacherAssessmentRecordOne(
  //     String classId, AssessmentTeacherQueryDto dto) async {
  //   List<QuestionRecord> result = [];
  //   try {
  //     EasyLoading.show();
  //     var response = await _schoolServiceProvider.getTeacherAssessmentRecords(
  //         classId, dto);
  //     if (response.statusCode == 200) {
  //       var data = assessmentRecordsResultFromJson(response.bodyString);
  //       if (data.list != null) {
  //         result.addAll(data.list!);
  //       }
  //     }
  //   } catch (error) {
  //     Log.debug(error);
  //   } finally {
  //     EasyLoading.dismiss();
  //   }
  //   return result;
  // }

  Future<FileLoactionResult> downloadGradeReport(String fileId) async {
    change(this._gradeReport, status: RxStatus.loading());
    try {
      EasyLoading.show();
      var response = await _schoolServiceProvider.downloadGradeReport(fileId);
      if (response.statusCode == 200) {
        var data = fileLoactionResultFromJson(response.bodyString);
        this._gradeReport.value = data;
        change(this._gradeReport, status: RxStatus.success());
      }
    } catch (error) {
      change(this._gradeReport, status: RxStatus.error());
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
    return this._gradeReport.value;
  }

  void fetchSingleAssingmentRecord(String classId, String id) async {
    try {
      //change(_singleAssignmentData, status: RxStatus.loading());
      EasyLoading.show();
      var response =
          await _schoolServiceProvider.getSignleAssignmentRecord(classId, id);
      if (response.statusCode == 200) {
        var data = singleAssignmentDataFromJson(response.bodyString);
        if (data.length > 0) {
          change(_singleAssignmentData, status: RxStatus.success());
          this._singleAssignmentData.assignAll(data);
        } else {
          change(_singleAssignmentData, status: RxStatus.empty());
        }
      }
    } catch (error) {
      Log.debug(error);
      change(_singleAssignmentData, status: RxStatus.error());
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchAssignmentStudentReport(
      String assignmentId, String userName) async {
    try {
      //change(_assignmentStudentData, status: RxStatus.loading());
      var response = await _schoolServiceProvider.getAssignmentStudentReport(
          assignmentId, userName);
      if (response.statusCode == 200) {
        var data = assignmentStudentDataFromJson(response.bodyString);
        change(_assignmentStudentData, status: RxStatus.success());
        this._assignmentStudentData.value = data;
      }
    } catch (error) {
      Log.debug(error);
      change(_assignmentStudentData, status: RxStatus.error());
    }
  }

  void fetchAssignmentReportForUser(
      String classId, String assignmentId, String userName) async {
    try {
      EasyLoading.show();
      //change(_assignmentStudentDetailList, status: RxStatus.loading());
      var response = await _schoolServiceProvider.getAssignmentReportForUser(
          classId, assignmentId, userName);
      if (response.statusCode == 200) {
        var data = assignmentStudentDetailFromJson(response.bodyString);
        if (data.length > 0) {
          change(_assignmentStudentDetailList, status: RxStatus.success());
          this._assignmentStudentDetailList.assignAll(data);
        } else {
          change(_assignmentStudentDetailList, status: RxStatus.empty());
        }
      }
    } catch (error) {
      Log.debug(error);
      change(_assignmentStudentDetailList, status: RxStatus.empty());
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchSelfReading(String userName, SelfReadingDto dto) async {
    try {
      //change(_selfReadingData, status: RxStatus.loading());
      EasyLoading.show();
      var response = await _schoolServiceProvider.getSelfReading(userName, dto);
      if (response.statusCode == 200) {
        var data = selfReadingDataFromJson(response.bodyString);
        change(_selfReadingData, status: RxStatus.success());
        this._selfReadingData.value = data;
      }
    } catch (error) {
      Log.debug(error);
      change(_selfReadingData, status: RxStatus.empty());
    } finally {
      EasyLoading.dismiss();
    }
  }

  // void fetchMySelfReading(SelfReadingDto dto) async {
  //   try {
  //     //change(_selfReadingData, status: RxStatus.loading());
  //     EasyLoading.show();
  //     var response = await _schoolServiceProvider.getMySelfReading(dto);
  //     if (response.statusCode == 200) {
  //       var data = selfReadingDataFromJson(response.bodyString);
  //       change(_selfReadingData, status: RxStatus.success());
  //       this._selfReadingData.value = data;
  //     }
  //   } catch (error) {
  //     Log.debug(error);
  //     change(_selfReadingData, status: RxStatus.empty());
  //   } finally {
  //     EasyLoading.dismiss();
  //   }
  // }

  Future<dynamic> fetchStudentQuizAttemp(String bookId, String userName) async {
    try {
      var response =
          await _schoolServiceProvider.getStudentQuizAttemp(bookId, userName);
      if (response.statusCode == 200) {
        var data = quizRecordDataFromJson(response.bodyString);
        this._quizRecordData.value = data;
        change(_quizRecordData, status: RxStatus.success());
      }
    } catch (error) {
      Log.debug(error);
      change(_quizRecordData, status: RxStatus.error());
    }
  }

  Future<dynamic> fetchBookQuiz(String bookId) async {
    try {
      var response = await _bookServiceProvider.getBookQuiz(bookId);
      if (response.statusCode == 200) {
        var data = bookQuizFromJson(response.bodyString);
        _bookquiz.value = data;
        change(_bookquiz, status: RxStatus.success());
      } else {
        change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    }
  }

  void fetchLibraryOverviewClassData(String classId) async {
    try {
      EasyLoading.show();
      var response =
          await _schoolServiceProvider.getLibraryOverviewClassData(classId);
      if (response.statusCode == 200) {
        var data = evaluationOverviewResultFromJson(response.bodyString);
        if (data.result != null) {
          _quickReviewOverviewResult.value =
              data.result as EvaluationOverViewData;
          change(_quickReviewOverviewResult, status: RxStatus.success());
        } else
          change(_quickReviewOverviewResult, status: RxStatus.empty());
      } else {
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void refresLibraryOverviewData(String classId) async {
    fetchLibraryOverviewClassData(classId);
  }

  void fetchLibraryKnowledgeClassData(String classId, String level) async {
    try {
      //change(_libraryKnowledgeClassData, status: RxStatus.loading());
      EasyLoading.show();
      var response = await _schoolServiceProvider.getLibraryKnowledgeClassData(
          classId, level);
      if (response.statusCode == 200) {
        var data = libraryKnowledgeClassResultFromJson(response.bodyString);
        if (data.result != null) {
          _libraryKnowledgeClassData.value =
              data.result as LibraryKnowledgeClassData;
          change(_libraryKnowledgeClassData, status: RxStatus.success());
        } else
          change(_libraryKnowledgeClassData, status: RxStatus.empty());
      } else {
        //change(null, status: RxStatus.error(response.statusCode.toString()));
        change(_libraryKnowledgeClassData, status: RxStatus.empty());
        Log.debug(response.body);
      }
    } catch (error) {
      //change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      change(_libraryKnowledgeClassData, status: RxStatus.empty());
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchLibraryRecords(String? classId) async {
    try {
      //change(_quickReviewLibraryRecordItems, status: RxStatus.loading());
      EasyLoading.show();
      var response = await _evaluationServiceProvider
          .getEvaluationRecordsByClass(null, null, 'LIBRARY', classId);
      if (response.statusCode == 200) {
        var data = assessmentRecordsResultFromJson(response.bodyString);
        _quickReviewLibraryRecordItems
            .assignAll(data.list as List<QuestionRecord>);
        if (_quickReviewLibraryRecordItems.length > 0) {
          _quickReviewLibraryRecordItems.sort((a, b) {
            var end1 = a.committedTime as int;
            var end2 = b.committedTime as int;
            return end2.compareTo(end1);
          });
        }
        change(_quickReviewLibraryRecordItems, status: RxStatus.success());
      } else {
        change(_quickReviewLibraryRecordItems, status: RxStatus.empty());
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchLibraryKnowledgeUserData(String level) async {
    try {
      EasyLoading.show();
      var response =
          await _schoolServiceProvider.getLibraryKnowledgeUserData(level);
      if (response.statusCode == 200) {
        var data = libraryKnowledgeUserResultFromJson(response.bodyString);
        if (data.result != null) {
          _libraryKnowledgeUserData.value =
              data.result as LibraryKnowledgeUserData;
          change(_libraryKnowledgeUserData, status: RxStatus.success());
        } else
          change(_libraryKnowledgeUserData, status: RxStatus.empty());
      } else {
        //change(null, status: RxStatus.error(response.statusCode.toString()));
        change(_libraryKnowledgeUserData, status: RxStatus.empty());
        Log.debug(response.body);
      }
    } catch (error) {
      //change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      change(_libraryKnowledgeUserData, status: RxStatus.empty());
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void fetchLibraryOverviewUserData() async {
    try {
      //change(_quickReviewOverviewResult, status: RxStatus.loading());
      EasyLoading.show();
      var response = await _schoolServiceProvider.getLibraryOverviewUserData();
      if (response.statusCode == 200) {
        var data = evaluationOverviewResultFromJson(response.bodyString);
        if (data.result != null) {
          _quickReviewOverviewResult.value =
              data.result as EvaluationOverViewData;
          change(_quickReviewOverviewResult, status: RxStatus.success());
        } else
          change(_quickReviewOverviewResult, status: RxStatus.empty());
      } else {
        //  change(null, status: RxStatus.error(response.statusCode.toString()));
        Log.debug(response.body);
      }
    } catch (error) {
      change(null, status: RxStatus.error('Oops, something wrong ...'.tr));
      Log.debug(error);
    } finally {
      EasyLoading.dismiss();
    }
  }

  void refetchStudentPersonalReport(String _classId, String _userName) {
    AssignmentSearchDto dto = new AssignmentSearchDto(
        assignmentType: "ASSIGNMENT",
        live: true,
        past: false,
        sortField: "-created");

    this.fetchClassStudentReportByClass(_classId, _userName, dto);

    if (studentPersonalReportTab == Constants.studentPersonalReportTabs[0]) {
      reportStudentPersonalOverviewKey.currentState?.fetchData(_userName);
    }
    if (studentPersonalReportTab == Constants.studentPersonalReportTabs[2]) {
      StudentActivityDto dto = new StudentActivityDto(
          from: DateTime.now()
              .add(Duration(days: -1 * 15))
              .millisecondsSinceEpoch,
          to: DateTime.now().millisecondsSinceEpoch);
      reportStudentPersonalActivityKey.currentState?.resetForm();
      reportStudentPersonalActivityKey.currentState
          ?.fetchOverallData(_classId, _userName, dto);
    }
    if (studentPersonalReportTab == Constants.studentPersonalReportTabs[3]) {
      reportsStudentPersonalSelfReadingKey.currentState?.resetForm();
      reportsStudentPersonalSelfReadingKey.currentState?.fetchOverallData(
          _userName,
          DateTime.now().add(Duration(days: -1 * 90)),
          DateTime.now(),
          false,
          false);
    }
    if (studentPersonalReportTab == Constants.studentPersonalReportTabs[4]) {
      reportsStudentPersonalAssignmentKey.currentState?.resetForm();
      reportsStudentPersonalAssignmentKey.currentState
          ?.fetchOverallData(_classId, _userName, null, null, null, true, true);
    }
    if (studentPersonalReportTab == Constants.studentPersonalReportTabs[5]) {
      reportsStudentPersonalAssessmentKey.currentState?.resetStatus();
      reportsStudentPersonalAssessmentKey.currentState
          ?.fetchOverallData(_classId, _userName, []);
    }
    if (studentPersonalReportTab == Constants.studentPersonalReportTabs[6]) {
      reportsStudentPersonalLevelKey.currentState?.fetchData(_userName);
    }
  }
}
